using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace VerticalProcesses
{
    public class MatrixWriter:OutputWriter
    {

        private Dictionary<string, StreamWriter> gruOutputFiles = new Dictionary<string, StreamWriter>();
        private Dictionary<string, StreamWriter> cduOutputFiles = new Dictionary<string, StreamWriter>();        
        private Dictionary<string,double[]> gruOutputValues = new Dictionary<string, double[]>();
        private Dictionary<string, double[]> cduOutputValues = new Dictionary<string, double[]>();        
        private bool outputDates = false;
        private DateTime[] outputThisDates;
        private string outputPath;
        //cdu variable are are in case the user wants to run gru processes only
        private string cduType;
        private string[] cduOutputVars;
        private Dictionary<string, bool> cduIDs;


        #region public methods

        public override void captureGruState(Dictionary<string, double> selectedVarsValues, int gruIndex)
        {
            // pull the selected vars out of hashtable into dictonary for each selected variable
            foreach (string variable in _gruOutputVars)
            {

                {
                    gruOutputValues[variable][gruIndex] = selectedVarsValues[variable];

                }

            }

        }
        public override void captureCduState(Dictionary<string, double> selectedVarsValues, int cduIndex)
        {
            // pull the selected vars out of dictionary into dictonary for each selected variable
            foreach (string variable in cduOutputVars)
            {

                {
                    cduOutputValues[variable][cduIndex] = selectedVarsValues[variable];

                }

            }

        }

        public override void write(DateTime currentDate)
        {
            if (cduType == null)
            {
                if (outputDates)
                {
                    writeDatesGRU(currentDate, outputThisDates);
                }
                else
                {
                    writeAllGRU(currentDate);
                }
            }
            else
            {
                if (outputDates)
                {
                    writeDatesGRU(currentDate, outputThisDates);
                    writeDatesCDU(currentDate, outputThisDates);
                }
                else
                {
                    writeAllGRU(currentDate);
                    writeAllCDU(currentDate);
                }
            
            
            }
        }


        public override void closeAll()
        {
            foreach (string variable in _gruOutputVars)
            {
                gruOutputFiles[variable].Close();
            
            }

        }

        #endregion


        // constructors
         
        public MatrixWriter(string gruType, string cduType, string outputPath,
            string[] gruOutputVars, string[] cduOutputVars, Dictionary<string, bool> gruIDs,
            Dictionary<string, bool> cduIDs, bool outputdates, DateTime[] outputThisDates)
            : base(gruType, outputPath, gruOutputVars, gruIDs)
  
        {
            this.outputDates = outputdates;
            this.outputThisDates = outputThisDates;
            this.outputPath = outputPath;
            this.cduType = cduType;
            this.cduOutputVars = cduOutputVars;
            this.cduIDs = cduIDs;
            initializeWriteGRU();
            initializeWriteCDU();
        }
        public MatrixWriter(string gruType, string outputPath, string[] gruOutputVars, Dictionary<string, bool> gruIDs,
       bool outputdates, DateTime[] outputThisDates) : base(gruType, outputPath, gruOutputVars, gruIDs)
        {
            this.outputDates = outputdates;
            this.outputThisDates = outputThisDates;
            initializeWriteGRU();

        }


        #region private methods


        private void initializeWriteGRU()
        {
            // open seperate streamwriters for each selected variable
            // create array to hold gru output for each 

            for (int i = 0; i < _gruOutputVars.Length; i++)
            {
                // dictionary that holds stream writers
                string fileName = _outputPath + _gruType + "-" + _gruOutputVars[i].ToString() + ".csv";
                StreamWriter writeVar = new StreamWriter(fileName, false);
                gruOutputFiles.Add(_gruOutputVars[i], writeVar);

                //write header lines
                string[] header = new string[_gruIDs.Keys.Count + 1];
                header[0] = "DateTime";
                _gruIDs.Keys.CopyTo(header, 1);
                string headerCsv = string.Join(",", header);
                writeVar.WriteLine(headerCsv, false);

                // dictionary that holds vectors for each selected variable
                double[] varsArray = new double[_gruIDs.Keys.Count];
                gruOutputValues.Add(_gruOutputVars[i], varsArray);

            }
        }
        private void initializeWriteCDU()
        {
            // open seperate streamwriters for each selected variable
            // create array to hold cdu output for each 

            for (int i = 0; i < cduOutputVars.Length; i++)
            {
                // dictionary that holds stream writers
                string fileName = _outputPath + cduType + "-" + cduOutputVars[i].ToString() + ".csv";
                StreamWriter writeVar = new StreamWriter(fileName, false);
                cduOutputFiles.Add(cduOutputVars[i], writeVar);

                //write header line
                string[] header = new string[cduIDs.Keys.Count + 1];
                header[0] = "DateTime";
                cduIDs.Keys.CopyTo(header, 1);
                string headerCsv = string.Join(",", header);
                writeVar.WriteLine(headerCsv, false);

                // dictionary that holds vectors for each selected variable
                double[] varsArray = new double[cduIDs.Keys.Count];
                cduOutputValues.Add(cduOutputVars[i], varsArray);

            }

        }

        private void writeAllGRU(DateTime currentDate)
        {

            foreach (string variable in _gruOutputVars)
            {

                string[] varOutput = new string[gruOutputValues[variable].Length + 1];
                varOutput[0] = currentDate.ToString();
                string[] temp = Array.ConvertAll<double, string>(gruOutputValues[variable], Convert.ToString);
                temp.CopyTo(varOutput, 1);

                string varOutputCsv = string.Join(",", varOutput);
                gruOutputFiles[variable].WriteLine(varOutputCsv);
            }
        }

        private void writeAllCDU(DateTime currentDate)
        {
            foreach (string variable in cduOutputVars)
            {

                string[] varOutput = new string[cduOutputValues[variable].Length + 1];
                varOutput[0] = currentDate.ToString();
                string[] temp = Array.ConvertAll<double, string>(cduOutputValues[variable], Convert.ToString);
                temp.CopyTo(varOutput, 1);

                string varOutputCsv = string.Join(",", varOutput);
                cduOutputFiles[variable].WriteLine(varOutputCsv);
            }

        }

        private void writeDatesGRU(DateTime currentDate, DateTime[] selecteDates)
        {
            foreach (DateTime date in selecteDates)
            {
                if (date == currentDate)
                {
                    foreach (string variable in _gruOutputVars)
                    {

                        string[] varOutput = new string[gruOutputValues[variable].Length + 1];
                        varOutput[0] = currentDate.ToString();
                        string[] temp = Array.ConvertAll<double, string>(gruOutputValues[variable], Convert.ToString);
                        temp.CopyTo(varOutput, 1);

                        string varOutputCsv = string.Join(",", varOutput);
                        gruOutputFiles[variable].WriteLine(varOutputCsv);
                    }
                }
            }
        }

        private void writeDatesCDU(DateTime currentDate, DateTime[] selecteDates)
        {
            foreach (DateTime date in selecteDates)
            {
                if (date == currentDate)
                    foreach (string variable in cduOutputVars)
                    {

                        string[] varOutput = new string[cduOutputValues[variable].Length + 1];
                        varOutput[0] = currentDate.ToString();
                        string[] temp = Array.ConvertAll<double, string>(cduOutputValues[variable], Convert.ToString);
                        temp.CopyTo(varOutput, 1);

                        string varOutputCsv = string.Join(",", varOutput);
                        cduOutputFiles[variable].WriteLine(varOutputCsv);
                    }

            }

        }
        #endregion

    }
}
